package yb.ecp.fast.infra.web;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.FastJsonUtil;
import yb.ecp.fast.infra.security.LoginFilter;

import javax.annotation.Resource;
import java.net.URI;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


@Controller
@RequestMapping("/parts")
@RefreshScope
@Slf4j
public class PartsController {

    private final Logger mylog = LoggerFactory.getLogger(this.getClass());
    @Resource(name = "gwRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    @Value("${hanyun.oauth2.main-front-url}")
    private String mainFrontUrl;
    @Value("${hanyun.oauth2.main-redirect-url}")
    private String mainDirectUrl;
    @Value("${hanyun.oauth2.ius-login-url}")
    private String iusHanyunOssLogin;

    @Value("${fast.auth.login.sessionTime:3000}")
    private Long sessionTime;

    @GetMapping("/login")
    public Mono<Void> partsLogin(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        String code = queryParams.getFirst("code");
        // 参数缺失处理
        if (StringUtils.isEmpty(code)) {
            String redirectUrl = mainFrontUrl;
            response.setStatusCode(HttpStatus.FOUND);
            response.getHeaders().setLocation(URI.create(redirectUrl));
            return response.setComplete();
        }
        // 异步处理用户认证
        return queryUserFromPartsReactive(code, iusHanyunOssLogin).flatMap(responseData -> {
                    if (!StringUtils.isEmpty(responseData)) {
                        try {
                            ActionResult<Map<String, Object>> result = FastJsonUtil.parse(responseData, ActionResult.class);
                            if (result != null && result.getValue() != null) {
                                Map<String, Object> authInfo = createAuthInfo(result.getValue());
                                storeAuthToken(authInfo.get("ScAuth").toString(), authInfo.get("userId"));
                                return Mono.just(mainDirectUrl + "?ScAuth=" + authInfo.get("ScAuth"));
                            }
                        } catch (Exception e) {
                            log.warn("Failed to process auth response: {}", e.getMessage());
                        }
                    }
                    return Mono.just(mainDirectUrl);
                }).defaultIfEmpty(mainDirectUrl) // 异常情况仍跳转
                .flatMap(url -> {
                    response.setStatusCode(HttpStatus.FOUND);
                    response.getHeaders().setLocation(URI.create(url));
                    return response.setComplete();
                });
    }

    private Map<String, Object> createAuthInfo(Object userId) {
        Map<String, Object> auth = new HashMap<>(2);
        auth.put("userId", userId);
        auth.put("ScAuth", UUID.randomUUID().toString());
        return auth;
    }

    private Mono<String> queryUserFromPartsReactive(String code, String devHanyunOssLogin) {
        return WebClient.create().get()
                .uri(devHanyunOssLogin, uri -> uri.queryParam("code", code).build())
                .retrieve().bodyToMono(String.class).timeout(Duration.ofSeconds(50));
    }

    private void storeAuthToken(String token, Object userId) {
        try {
            redisTemplate.opsForValue().set(LoginFilter.REDIS_KEY_PREFIX + token, userId, Duration.ofSeconds(sessionTime));
        } catch (Exception e) {
            mylog.error("Failed to store auth token: {}", e.getMessage());
        }
    }
}
